
#include "xparameters.h"

#include "netif/xadapter.h"

#include "platform.h"
#include "platform_config.h"
#if defined (__arm__) || defined(__aarch64__)
#include "xil_printf.h"
#endif

#include "lwip/tcp.h"
#include "xil_cache.h"

#include "lwip/dhcp.h"


#include "netif/xemacpsif.h"
#include "lwipopts.h"
#include "xparameters_ps.h"
#include "xparameters.h"


#include "xaxidma.h"
#include "xparameters.h"
#include "xil_exception.h"
#include "xdebug.h"
#include "xil_cache.h"
#include "xtime_l.h"


#ifdef __aarch64__
#include "xil_mmu.h"
#endif

#ifdef XPAR_UARTNS550_0_BASEADDR
#include "xuartns550_l.h"       /* to use uartns550 */
#endif

#ifndef DEBUG
extern void xil_printf(const char *format, ...);
#endif

#ifdef XPAR_INTC_0_DEVICE_ID
 #include "xintc.h"
#else
 #include "xscugic.h"
#endif

/******************** Constant Definitions **********************************/
/*
 * Device hardware build related constants.
 */

#define DMA_DEV_ID		XPAR_AXIDMA_0_DEVICE_ID

#ifdef XPAR_AXI_7SDDR_0_S_AXI_BASEADDR
#define DDR_BASE_ADDR		XPAR_AXI_7SDDR_0_S_AXI_BASEADDR
#elif XPAR_MIG7SERIES_0_BASEADDR
#define DDR_BASE_ADDR	XPAR_MIG7SERIES_0_BASEADDR
#elif XPAR_MIG_0_BASEADDR
#define DDR_BASE_ADDR	XPAR_MIG_0_BASEADDR
#elif XPAR_PSU_DDR_0_S_AXI_BASEADDR
#define DDR_BASE_ADDR	XPAR_PSU_DDR_0_S_AXI_BASEADDR
#endif

#ifndef DDR_BASE_ADDR
#warning CHECK FOR THE VALID DDR ADDRESS IN XPARAMETERS.H, \
			DEFAULT SET TO 0x01000000
#define MEM_BASE_ADDR		0x01000000
#else
#define MEM_BASE_ADDR		(DDR_BASE_ADDR + 0x1000000)
#endif

#ifdef XPAR_INTC_0_DEVICE_ID
#define RX_INTR_ID		XPAR_INTC_0_AXIDMA_0_S2MM_INTROUT_VEC_ID
#define TX_INTR_ID		XPAR_INTC_0_AXIDMA_0_MM2S_INTROUT_VEC_ID
#else
#define RX_INTR_ID		XPAR_FABRIC_AXI_DMA_0_S2MM_INTROUT_INTR
#endif


#define RX_BD_SPACE_BASE1	(0x01000000 )
#define RX_BD_SPACE_HIGH1	(0x01000000 + 0x00003FF)

#define RX_BUFFER_BASE		(0x01000000 + 0x00300000)
#define RX_BUFFER_HIGH		(0x01000000 + 0x004FFFFF)

#define RX_BUFFER_BASE1		(0x01000000 + 0x00500000)
#define RX_BUFFER_HIGH1		(0x01000000 + 0x006FFFFF)

#ifdef XPAR_INTC_0_DEVICE_ID
#define INTC_DEVICE_ID          XPAR_INTC_0_DEVICE_ID
#else
#define INTC_DEVICE_ID          XPAR_SCUGIC_SINGLE_DEVICE_ID
#endif

/* Timeout loop counter for reset
 */
#define RESET_TIMEOUT_COUNTER	10000

/*
 * Buffer and Buffer Descriptor related constant definition
 */
#define MAX_PKT_LEN		128
#define MARK_UNCACHEABLE        0x701

/*
 * Number of BDs in the transfer example
 * We show how to submit multiple BDs for one transmit.
 * The receive side gets one completion per transfer.
 */
#define NUMBER_OF_BDS_PER_PKT		1
#define NUMBER_OF_PKTS_TO_TRANSFER 	100
#define NUMBER_OF_BDS_TO_TRANSFER	(NUMBER_OF_PKTS_TO_TRANSFER * \
						NUMBER_OF_BDS_PER_PKT)

/* The interrupt coalescing threshold and delay timer threshold
 * Valid range is 1 to 255
 *
 * We set the coalescing threshold to be the total number of packets.
 * The receive side will only get one completion interrupt for this example.
 */
#define COALESCING_COUNT		NUMBER_OF_PKTS_TO_TRANSFER
#define DELAY_TIMER_COUNT		100

#ifdef XPAR_INTC_0_DEVICE_ID
 #define INTC		XIntc
 #define INTC_HANDLER	XIntc_InterruptHandler
#else
 #define INTC		XScuGic
 #define INTC_HANDLER	XScuGic_InterruptHandler
#endif

/**************************** Type Definitions *******************************/


/***************** Macros (Inline Functions) Definitions *********************/


/************************** Function Prototypes ******************************/
#ifdef XPAR_UARTNS550_0_BASEADDR
static void Uart550_Setup(void);
#endif

static void RxCallBack(XAxiDma_BdRing * RxRingPtr);
static void RxIntrHandler(void *Callback);



static int SetupIntrSystem(INTC * IntcInstancePtr,
			   XAxiDma * AxiDmaPtr, u16 TxIntrId, u16 RxIntrId);
static void DisableIntrSystem(INTC * IntcInstancePtr,
					u16 TxIntrId, u16 RxIntrId);

static int RxSetup(XAxiDma * AxiDmaInstPtr);
static int RxSetupAgain(XAxiDma * AxiDmaInstPtr);

/************************** Variable Definitions *****************************/
/*
 * Device instance definitions
 */
XAxiDma AxiDma;
#define COUNTS_PER_USECOND  (XPAR_CPU_CORTEXA9_CORE_CLOCK_FREQ_HZ / (2U*1000000U))


static INTC Intc;	/* Instance of the Interrupt Controller */

/*
 * Flags interrupt handlers use to notify the application context the events.
 */
volatile int TxDone;
volatile int RxDone;
volatile int RxDoneAll = 0;

volatile int Error;


XAxiDma_BdRing *RxRingPtr;
XAxiDma_Bd *gBdPtr = NULL;
int gBdCount = 0;
XAxiDma_Bd *gCurrentBdPtr = NULL;
UINTPTR gCurretBufferPtr = 0;


extern volatile int TcpFastTmrFlag;
extern volatile int TcpSlowTmrFlag;
static struct netif server_netif;
struct netif *echo_netif;

extern volatile int dhcp_timoutcntr;
err_t dhcp_start(struct netif *netif);

int CleadBD(XAxiDma_Bd* bd,int len);
void StartBdTransmission(XAxiDma * AxiDmaInstPtr,XAxiDma_Bd* bd,int count);
void ReStartBdTransmission(XAxiDma * AxiDmaInstPtr,XAxiDma_Bd* bd,int count);


#define IEEE_CONTROL_REG_OFFSET					0
#define IEEE_STATUS_REG_OFFSET					1
#define IEEE_AUTONEGO_ADVERTISE_REG				4
#define IEEE_PARTNER_ABILITIES_1_REG_OFFSET		5
#define IEEE_PARTNER_ABILITIES_2_REG_OFFSET		8
#define IEEE_PARTNER_ABILITIES_3_REG_OFFSET		10
#define IEEE_1000_ADVERTISE_REG_OFFSET			9
#define IEEE_MMD_ACCESS_CONTROL_REG		        13
#define IEEE_MMD_ACCESS_ADDRESS_DATA_REG		14
#define IEEE_COPPER_SPECIFIC_CONTROL_REG		16
#define IEEE_SPECIFIC_STATUS_REG				17
#define IEEE_COPPER_SPECIFIC_STATUS_REG_2		19
#define IEEE_EXT_PHY_SPECIFIC_CONTROL_REG   	20
#define IEEE_CONTROL_REG_MAC					21
#define IEEE_PAGE_ADDRESS_REGISTER				22


void InitLWIP(){
	struct ip_addr ipaddr, netmask, gw;

	/* the mac address of the board. this should be unique per board */
	unsigned char mac_ethernet_address[] =
	{ 0x00, 0x0a, 0x35, 0x00, 0x01, 0x02 };
	echo_netif = &server_netif;
	init_platform();


	/* initliaze IP addresses to be used */
	IP4_ADDR(&ipaddr,  192, 168,   5, 133);
	IP4_ADDR(&netmask, 255, 255, 255,  0);
	IP4_ADDR(&gw,      192, 168,   5,  1);


	lwip_init();
	/* Add network interface to the netif_list, and set it as default */
	if (!xemac_add(echo_netif, &ipaddr, &netmask,
						&gw, mac_ethernet_address,
						PLATFORM_EMAC_BASEADDR)) {
		xil_printf("Error adding N/W interface\n\r");
		return -1;
	}
	netif_set_default(echo_netif);
	/* now enable interrupts */
	platform_enable_interrupts();
	/* specify that the network if is up */
	netif_set_up(echo_netif);
	struct xemac_s *emac = (struct xemac_s *)echo_netif->state;
	if(emac  != NULL){
		xemacpsif_s *xemacpsif = (xemacpsif_s*)emac->state;
		if(xemacpsif != NULL){
			xil_printf("\r\nxemacpsif %ld\r\n",xemacpsif);
			u16 status;
			XEmacPs_PhyRead(&xemacpsif->emacps, 0, IEEE_STATUS_REG_OFFSET, &status);

			xil_printf("IEEE_STATUS_REG_OFFSET 0x%04x\r\n",status);
		}
	}
	/* Create a new DHCP client for this interface.
	 * Note: you must call dhcp_fine_tmr() and dhcp_coarse_tmr() at
	 * the predefined regular intervals after starting the client.
	 */
	dhcp_start(echo_netif);
	dhcp_timoutcntr = 24;

	while(((echo_netif->ip_addr.addr) == 0)
			&& (dhcp_timoutcntr > 0))
		xemacif_input(echo_netif);

	if (dhcp_timoutcntr <= 0) {
		if ((echo_netif->ip_addr.addr) == 0) {
			xil_printf("DHCP Timeout\r\n");
			xil_printf("Configuring default IP of 192.168.1.10\r\n");
			IP4_ADDR(&(echo_netif->ip_addr),  192, 168,   5, 133);
			IP4_ADDR(&(echo_netif->netmask), 255, 255, 255,  0);
			IP4_ADDR(&(echo_netif->gw),      192, 168,   5,  1);
		}
	}

	ipaddr.addr = echo_netif->ip_addr.addr;
	gw.addr = echo_netif->gw.addr;
	netmask.addr = echo_netif->netmask.addr;
}

void littledelay(){
	for(int i = 0;i < 100;i++){
		
	}
}
int main(void)
{
	int Status;
	XAxiDma_Config *Config;
	
	RxDone = 0;
	Error = 0;
	/* Initial setup for Uart16550 */
#ifdef XPAR_UARTNS550_0_BASEADDR
	Uart550_Setup();
#endif
	Xil_DCacheDisable();
	Xil_ICacheDisable();

	Xil_Out32(0xF8000008,0xDF0D);  //57101==0DF0D 
	Xil_Out32(0xF8000240,2);//发出FCLK_RESET0_N=1
	littledelay();
	Xil_Out32(0xF8000240,0);//发出FCLK_RESET0_N=1
	Xil_Out32(0xF8000008,0x767B);  //57101==0DF0D 
//	InitLWIP();
	
	xil_printf("\r\n--- Entering main() --- \r\n");
#ifdef __aarch64__
	Xil_SetTlbAttributes(TX_BD_SPACE_BASE, MARK_UNCACHEABLE);
	Xil_SetTlbAttributes(RX_BD_SPACE_BASE, MARK_UNCACHEABLE);
#endif
	Config = XAxiDma_LookupConfig(DMA_DEV_ID);
	if (!Config) {
		xil_printf("No config found for %d\r\n", DMA_DEV_ID);
		return XST_FAILURE;
	}

	/* Initialize DMA engine */
	XAxiDma_CfgInitialize(&AxiDma, Config);
	
	XAxiDma_Reset(&AxiDma);
	littledelay();

	int TimeOut = RESET_TIMEOUT_COUNTER;
	while (TimeOut) {
		if(XAxiDma_ResetIsDone(&AxiDma)) {
			xil_printf("reset axi dma %d is done\r\n", DMA_DEV_ID);

			break;
		}
		TimeOut -= 1;
	}
	
	if(!XAxiDma_HasSg(&AxiDma)) {
		xil_printf("Device configured as Simple mode \r\n");
		return XST_FAILURE;
	}
	xil_printf("111\r\n");

	/* Set up Interrupt system  */
	Status = SetupIntrSystem(&Intc, &AxiDma, 0, RX_INTR_ID);
	if (Status != XST_SUCCESS) {
		xil_printf("Failed intr setup\r\n");
		return XST_FAILURE;
	}
	 XScuGic_CPUWriteReg(&Intc, XSCUGIC_EOI_OFFSET, 61);
	 
	Status = RxSetup(&AxiDma);
	if (Status != XST_SUCCESS) {
		xil_printf("Failed RX setup\r\n");
//		return XST_FAILURE;
	}
	xil_printf("222\r\n");


	XAxiDma_BdRing *RxRingPtr = XAxiDma_GetRxRing(&AxiDma);
	xil_printf("333\r\n");

	XAxiDma_BdRingDumpRegs(RxRingPtr);

	xil_printf("444\r\n");

	XTime tCur,tLast;
	/* Initialize flags before start transfer test  */
	XTime_GetTime(&tCur);
	tLast = tCur;

	while(1){
		if(RxDone >= 15){
//			xil_printf("RxDone %d\r\n",RxDone);

			RxDone = 0;
//			xil_printf("post:%d /%d\r\n",RxRingPtr->PostCnt,RxRingPtr->AllCnt);

			XTime_GetTime(&tCur);
			if((tLast != 0)&&((tCur - tLast) > XPAR_CPU_CORTEXA9_CORE_CLOCK_FREQ_HZ) ){
				xil_printf("RxDoneAll qeual %d \r\n",RxDoneAll);
				tLast = tCur;
			}
			
			
			XAxiDma_Bd *BdCurPtr = gCurrentBdPtr;
//			xil_printf("current bd: %x",XAxiDma_BdRingGetCurrBd(RxRingPtr));
			int BdCount = XAxiDma_BdRingFromHw(RxRingPtr, XAXIDMA_ALL_BDS, &BdCurPtr);
//			xil_printf("BdCount %d\r\n",BdCount);

			Status = XAxiDma_BdRingFree(RxRingPtr, BdCount, gCurrentBdPtr); // Return the list
			if (Status != XST_SUCCESS) {
				xil_printf("Failed XAxiDma_BdRingFree %d intc\r\n",Status);
			}
	
			for (int Index = 0; Index < BdCount; Index++) {
				int32_t* ptr = XAxiDma_BdGetBufAddr(BdCurPtr);
				int len = XAxiDma_BdGetActualLength(BdCurPtr,0xfffff);
				int BdSts = XAxiDma_BdGetSts(BdCurPtr);
				if(BdSts & XAXIDMA_BD_STS_COMPLETE_MASK){
//					xil_printf("bd ptr %x   sts: %x ptr: 0x%x  len:%d first: 0x%x \r\n",
//							BdCurPtr,BdSts,ptr,len,ptr[0]);
					RxDoneAll++;
				}
				if(BdSts & XAXIDMA_BD_STS_DEC_ERR_MASK){
					xil_printf("XAXIDMA_BD_STS_DEC_ERR_MASK bd ptr %x   sts: %x ptr: 0x%x  len:%d first: 0x%x \r\n",
							BdCurPtr,BdSts,ptr,len,ptr[0]);
				}
				if(BdSts & XAXIDMA_BD_STS_SLV_ERR_MASK){
					xil_printf("XAXIDMA_BD_STS_SLV_ERR_MASK bd ptr %x   sts: %x ptr: 0x%x  len:%d first: 0x%x \r\n",
							BdCurPtr,BdSts,ptr,len,ptr[0]);
				}		
				if(BdSts & XAXIDMA_BD_STS_INT_ERR_MASK){
					xil_printf("XAXIDMA_BD_STS_INT_ERR_MASK bd ptr %x   sts: %x ptr: 0x%x  len:%d first: 0x%x \r\n",
							BdCurPtr,BdSts,ptr,len,ptr[0]);
				}		
			
				XAxiDma_BdWrite(BdCurPtr,XAXIDMA_BD_STS_OFFSET,0);
				BdCurPtr = (XAxiDma_Bd *)XAxiDma_BdRingNext(RxRingPtr, BdCurPtr);
			}
		#ifdef __aarch64__
			Xil_DCacheFlushRange((UINTPTR)RX_BUFFER_BASE, MAX_PKT_LEN *
									NUMBER_OF_BDS_TO_TRANSFER);
		#endif
			if(RxRingPtr->FreeCnt == RxRingPtr->AllCnt){
				Status = RxSetupAgain(&AxiDma);
				if (Status != XST_SUCCESS) {
					xil_printf("Failed  RxSetupAgain\r\n");
	//				return XST_FAILURE;
				}
			}else{
				
			}

		} 
	}

	/* Disable TX and RX Ring interrupts and return success */
	DisableIntrSystem(&Intc, 0, RX_INTR_ID);
Done:
	xil_printf("--- Exiting main() --- \r\n");
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}
	return XST_SUCCESS;
}


static void RxCallBack(XAxiDma_BdRing * RxRingPtr)
{
	RxDone ++;
}

static void RxIntrHandler(void *Callback) {
	XAxiDma_BdRing *RxRingPtr = (XAxiDma_BdRing *) Callback;
	u32 IrqStatus;
	int TimeOut;

	int FreeBdCount = XAxiDma_BdRingGetFreeCnt(RxRingPtr);
//	xil_printf("RxIntrHandler FreeBdCount %d\r\n",FreeBdCount);

	/* Read pending interrupts */
	IrqStatus = XAxiDma_BdRingGetIrq(RxRingPtr);
//	xil_printf("RxIntrHandler IrqStatus 0x%x\r\n",IrqStatus);

	/* Acknowledge pending interrupts */
	XAxiDma_BdRingAckIrq(RxRingPtr, IrqStatus);

	/* Read pending interrupts */
//	IrqStatus = XAxiDma_BdRingGetIrq(RxRingPtr);
//	xil_printf("RxIntrHandler IrqStatus after ack 0x%x\r\n",IrqStatus);
	/*
	 * If no interrupt is asserted, we do not do anything
	 */
	if (!(IrqStatus & XAXIDMA_IRQ_ALL_MASK)) {
		return;
	}
	/*
	 * If error interrupt is asserted, raise error flag, reset the
	 * hardware to recover from the error, and return with no further
	 * processing.
	 */
	if ((IrqStatus & XAXIDMA_IRQ_ERROR_MASK)) {
		
		xil_printf("reseting\r\n");
		XAxiDma_BdRingDumpRegs(RxRingPtr);
		Error = 1;
		/* Reset could fail and hang
		 * NEED a way to handle this or do not call it??
		 */
		XAxiDma_Reset(&AxiDma);
		TimeOut = RESET_TIMEOUT_COUNTER;
		while (TimeOut) {
			if(XAxiDma_ResetIsDone(&AxiDma)) {
				RxCallBack(RxRingPtr);
				break;
			}
			TimeOut -= 1;
		}
		return;
	}
	/*
	 * If completion interrupt is asserted, call RX call back function
	 * to handle the processed BDs and then raise the according flag.
	 */
	if ((IrqStatus & (XAXIDMA_IRQ_IOC_MASK))) {
		RxCallBack(RxRingPtr);
	}
	/* Read pending interrupts */
	IrqStatus = XAxiDma_BdRingGetIrq(RxRingPtr);
//	xil_printf("RxIntrHandler IrqStatus 0x%x\r\n",IrqStatus);
	FreeBdCount = XAxiDma_BdRingGetFreeCnt(RxRingPtr);
//	xil_printf("RxIntrHandler FreeBdCount %d\r\n",FreeBdCount);
//	XAxiDma_BdRingDumpRegs(RxRingPtr);
	XAxiDma_BdRingAckIrq(RxRingPtr, IrqStatus);

}


static int SetupIntrSystem(INTC * IntcInstancePtr,
			   XAxiDma * AxiDmaPtr, u16 TxIntrId, u16 RxIntrId)
{
	XAxiDma_BdRing *TxRingPtr = XAxiDma_GetTxRing(AxiDmaPtr);
	XAxiDma_BdRing *RxRingPtr = XAxiDma_GetRxRing(AxiDmaPtr);
	int Status;

#ifdef XPAR_INTC_0_DEVICE_ID

	/* Initialize the interrupt controller and connect the ISRs */
	Status = XIntc_Initialize(IntcInstancePtr, INTC_DEVICE_ID);
	if (Status != XST_SUCCESS) {

		xil_printf("Failed init intc\r\n");
		return XST_FAILURE;
	}


	Status = XIntc_Connect(IntcInstancePtr, RxIntrId,
			       (XInterruptHandler) RxIntrHandler, RxRingPtr);
	if (Status != XST_SUCCESS) {

		xil_printf("Failed rx connect intc\r\n");
		return XST_FAILURE;
	}

	/* Start the interrupt controller */
	Status = XIntc_Start(IntcInstancePtr, XIN_REAL_MODE);
	if (Status != XST_SUCCESS) {

		xil_printf("Failed to start intc\r\n");
		return XST_FAILURE;
	}
	XIntc_Enable(IntcInstancePtr, RxIntrId);

#else
	XScuGic_Config *IntcConfig;

	/*
	 * Initialize the interrupt controller driver so that it is ready to
	 * use.
	 */
	IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
	if (NULL == IntcConfig) {
		return XST_FAILURE;
	}

	Status = XScuGic_CfgInitialize(IntcInstancePtr, IntcConfig,
					IntcConfig->CpuBaseAddress);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	Status = XScuGic_Connect(IntcInstancePtr, RxIntrId,
				(Xil_InterruptHandler)RxIntrHandler,
				RxRingPtr);
	if (Status != XST_SUCCESS) {
		return Status;
	}

	XScuGic_Enable(IntcInstancePtr, TxIntrId);
	XScuGic_Enable(IntcInstancePtr, RxIntrId);
#endif
	/* Enable interrupts from the hardware */
	Xil_ExceptionInit();
	Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
			(Xil_ExceptionHandler)INTC_HANDLER,
			(void *)IntcInstancePtr);

	Xil_ExceptionEnable();

	return XST_SUCCESS;
}

static void DisableIntrSystem(INTC * IntcInstancePtr,
					u16 TxIntrId, u16 RxIntrId)
{
#ifdef XPAR_INTC_0_DEVICE_ID
	/* Disconnect the interrupts for the DMA TX and RX channels */
	XIntc_Disconnect(IntcInstancePtr, TxIntrId);
	XIntc_Disconnect(IntcInstancePtr, RxIntrId);
#else
	XScuGic_Disconnect(IntcInstancePtr, TxIntrId);
	XScuGic_Disconnect(IntcInstancePtr, RxIntrId);
#endif
}


void AStartBdTransmission(XAxiDma * AxiDmaInstPtr,XAxiDma_Bd* bd,int count){
	xil_printf("111 %x %x \r\n",AxiDmaInstPtr,bd);
	RxRingPtr = XAxiDma_GetRxRing(AxiDmaInstPtr);
//	XAxiDma_BdRingDumpRegs(RxRingPtr);
	sleep(1);
	
	int Status = XAxiDma_BdRingToHw(RxRingPtr, 1024, bd);
	if (Status != XST_SUCCESS) {
		xil_printf("Rx ToHw failed with %d\r\n", Status);
		return ;
	}
	xil_printf("StartBdTransmission\r\n");
	
	/* Enable all RX interrupts */
	XAxiDma_BdRingIntEnable(RxRingPtr, XAXIDMA_IRQ_ALL_MASK);
	/* Start RX DMA channel */
	xil_printf("XAxiDma_BdRingIntEnable \r\n");
	XAxiDma_BdRingDumpRegs(RxRingPtr);

	Status = XAxiDma_BdRingStart(RxRingPtr);
	if (Status != XST_SUCCESS) {
		xil_printf("Rx start BD ring failed with %d\r\n", Status);
		return ;
	}
	xil_printf("StartBdTransmission after start\r\n");
	XAxiDma_BdRingDumpRegs(RxRingPtr);
}



void GetBufferData(){
	RxRingPtr = XAxiDma_GetRxRing(&AxiDma);
	
}
void ReStartBdTransmission(XAxiDma * AxiDmaInstPtr,XAxiDma_Bd* bd,int count){
	XAxiDma_Bd BdTemplate;
	RxRingPtr = XAxiDma_GetRxRing(&AxiDma);
	
	int FreeBdCount = XAxiDma_BdRingGetFreeCnt(RxRingPtr);
	xil_printf("ReStartBdTransmission FreeBdCount %d\r\n",FreeBdCount);
	
	int Status = XAxiDma_BdRingAlloc(RxRingPtr, FreeBdCount, &bd);
	if (Status != XST_SUCCESS) {
		xil_printf("Rx bd alloc failed with %d\r\n", Status);
		return ;
	}
	
	Status = XAxiDma_BdRingToHw(RxRingPtr, FreeBdCount, bd);
	if (Status != XST_SUCCESS) {
		xil_printf("Rx ToHw failed with %d\r\n", Status);
		return ;
	}

	xil_printf("StartBdTransmission\r\n");
	/* Enable all RX interrupts */
	XAxiDma_BdRingIntEnable(RxRingPtr, XAXIDMA_IRQ_ALL_MASK);
	/* Start RX DMA channel */

	Status = XAxiDma_BdRingStart(RxRingPtr);
	if (Status != XST_SUCCESS) {
		xil_printf("Rx start BD ring failed with %d\r\n", Status);
		return ;
	}
	XAxiDma_BdRingDumpRegs(RxRingPtr);

	xil_printf("StartBdTransmission after start\r\n");
}

static int RxSetup(XAxiDma * AxiDmaInstPtr)
{
	XAxiDma_BdRing *RxRingPtr;
	int Status;
	XAxiDma_Bd BdTemplate;
	XAxiDma_Bd *BdPtr;
	XAxiDma_Bd *BdCurPtr;
	int BdCount;
	int FreeBdCount;
	UINTPTR RxBufferPtr;
	int Index;

	RxRingPtr = XAxiDma_GetRxRing(&AxiDma);

	/* Disable all RX interrupts before RxBD space setup */
	XAxiDma_BdRingIntDisable(RxRingPtr, XAXIDMA_IRQ_ALL_MASK);

	/* Setup Rx BD space */
	BdCount = XAxiDma_BdRingCntCalc(XAXIDMA_BD_MINIMUM_ALIGNMENT,
				RX_BD_SPACE_HIGH1 - RX_BD_SPACE_BASE1 + 1);

	gBdCount = BdCount; 
	
	XAxiDma_BdRingIntEnable(RxRingPtr, XAXIDMA_IRQ_ALL_MASK);

	Status = XAxiDma_BdRingCreate(RxRingPtr, RX_BD_SPACE_BASE1,
					RX_BD_SPACE_BASE1,
					XAXIDMA_BD_MINIMUM_ALIGNMENT, BdCount);
	if (Status != XST_SUCCESS) {
		xil_printf("Rx bd create failed with %d\r\n", Status);
		return XST_FAILURE;
	}

	XAxiDma_BdClear(&BdTemplate);
	Status = XAxiDma_BdRingClone(RxRingPtr, &BdTemplate);
	if (Status != XST_SUCCESS) {
		xil_printf("Rx bd clone failed with %d\r\n", Status);
		return XST_FAILURE;
	}

	/* Attach buffers to RxBD ring so we are ready to receive packets */
	FreeBdCount = XAxiDma_BdRingGetFreeCnt(RxRingPtr);

	Status = XAxiDma_BdRingAlloc(RxRingPtr, FreeBdCount, &BdPtr);
	if (Status != XST_SUCCESS) {
		xil_printf("Rx bd alloc failed with %d\r\n", Status);
		return XST_FAILURE;
	}

	BdCurPtr = BdPtr;
	gBdPtr = BdPtr;

	if(gCurretBufferPtr == 0)
		gCurretBufferPtr = RX_BUFFER_BASE;
	else{
		if(gCurretBufferPtr == RX_BUFFER_BASE)
			gCurretBufferPtr = RX_BUFFER_BASE1;
		else{
			gCurretBufferPtr = RX_BUFFER_BASE;
		}
	}

	RxBufferPtr = gCurretBufferPtr;
	gBdCount = FreeBdCount;

	for (Index = 0; Index < FreeBdCount; Index++) {
		Status = XAxiDma_BdSetBufAddr(BdCurPtr, RxBufferPtr);
		if (Status != XST_SUCCESS) {
			xil_printf("Rx set buffer addr %x on BD %x failed %d\r\n",
			(unsigned int)RxBufferPtr,
			(UINTPTR)BdCurPtr, Status);
			return XST_FAILURE;
		}

		Status = XAxiDma_BdSetLength(BdCurPtr, MAX_PKT_LEN,
					RxRingPtr->MaxTransferLen);
		if (Status != XST_SUCCESS) {
			xil_printf("Rx set length %d on BD %x failed %d\r\n",
				MAX_PKT_LEN, (UINTPTR)BdCurPtr, Status);

			return XST_FAILURE;
		}

		XAxiDma_BdSetCtrl(BdCurPtr, 0);
		XAxiDma_BdSetId(BdCurPtr, RxBufferPtr);
		RxBufferPtr += MAX_PKT_LEN;
		BdCurPtr = (XAxiDma_Bd *)XAxiDma_BdRingNext(RxRingPtr, BdCurPtr);
	}

	Status = XAxiDma_BdRingToHw(RxRingPtr, FreeBdCount, BdPtr);
	if (Status != XST_SUCCESS) {
		xil_printf("Rx ToHw failed with %d\r\n", Status);
		return XST_FAILURE;
	}

	/* Enable all RX interrupts */

	/* Start RX DMA channel */
	Status = XAxiDma_BdRingStart(RxRingPtr);
	if (Status != XST_SUCCESS) {
		xil_printf("Rx start BD ring failed with %d\r\n", Status);
		return XST_FAILURE;
	}
	gCurrentBdPtr = BdPtr;
	return XST_SUCCESS;
}


static int RxSetupAgain(XAxiDma * AxiDmaInstPtr)
{
	XAxiDma_BdRing *RxRingPtr;
	int Status;
	XAxiDma_Bd *BdPtr;
	XAxiDma_Bd *BdCurPtr;
	UINTPTR RxBufferPtr;
	int Index;

//	xil_printf("RxSetupAgain\r\n");
	RxRingPtr = XAxiDma_GetRxRing(&AxiDma);

	BdCurPtr = gBdPtr;


	if(gCurretBufferPtr == 0)
		gCurretBufferPtr = RX_BUFFER_BASE;
	else{
		if(gCurretBufferPtr == RX_BUFFER_BASE)
			gCurretBufferPtr = RX_BUFFER_BASE1;
		else{
			gCurretBufferPtr = RX_BUFFER_BASE;
		}
	}

	RxBufferPtr = gCurretBufferPtr;
	XAxiDma_BdRingAlloc(RxRingPtr,  gBdCount,
		&BdCurPtr);
	
	for (Index = 0; Index < gBdCount; Index++) {
		Status = XAxiDma_BdSetBufAddr(BdCurPtr, RxBufferPtr);
		if (Status != XST_SUCCESS) {
			xil_printf("Rx set buffer addr %x on BD %x failed %d\r\n",
			(unsigned int)RxBufferPtr,
			(UINTPTR)BdCurPtr, Status);
			return XST_FAILURE;
		}

		Status = XAxiDma_BdSetLength(BdCurPtr, MAX_PKT_LEN,
					RxRingPtr->MaxTransferLen);
		if (Status != XST_SUCCESS) {
			xil_printf("Rx set length %d on BD %x failed %d\r\n",
				MAX_PKT_LEN, (UINTPTR)BdCurPtr, Status);

			return XST_FAILURE;
		}

		XAxiDma_BdSetCtrl(BdCurPtr, 0);
		XAxiDma_BdSetId(BdCurPtr, RxBufferPtr);
		RxBufferPtr += MAX_PKT_LEN;
		BdCurPtr = (XAxiDma_Bd *)XAxiDma_BdRingNext(RxRingPtr, BdCurPtr);
	}

	Status = XAxiDma_BdRingToHw(RxRingPtr, gBdCount, gBdPtr);
	if (Status != XST_SUCCESS) {
		xil_printf("Rx ToHw failed with %d\r\n", Status);
		return XST_FAILURE;
	}
	return XST_SUCCESS;
}

int CleadBD(XAxiDma_Bd* bd,int len){
		
	return 0;
}